Skip to content

feat: rework manager api for cross-major calls - #8

Open
kp2pml30 wants to merge 1 commit into
v0.3-devfrom
pr/v0.3/feat/rework-manager-api
Open

feat: rework manager api for cross-major calls#8
kp2pml30 wants to merge 1 commit into
v0.3-devfrom
pr/v0.3/feat/rework-manager-api

Conversation

@kp2pml30

@kp2pml30 kp2pml30 commented Jul 28, 2026

Copy link
Copy Markdown
Member

Auto-opened executor mirror of genlayerlabs/genvm-manager#9.

Carries the executor-side work for that manager PR. Auto-closed as merged when the manager PR lands (its pr/v0.3/feat/rework-manager-api branch is moved onto v0.3-dev).

Summary by CodeRabbit

  • New Features
    • Added support for true and false values in expressions, including comparisons, conditions, collections, and bindings.
    • Improved nested contract execution with routing, permission handling, recursion, memory, and deterministic fuel controls.
    • Added host handshake data and nested execution support.
  • Bug Fixes
    • Prevented invalid or uninstalled runners from loading and improved related error reporting.
    • Made precompiled module writes crash-safe.
    • Corrected result hashing and boolean type validation.
  • Documentation
    • Clarified major-version mismatch behavior in the public ABI.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds boolean literals to the expression language and expands nested execution with delegated routing, permissions, resource budgets, recursion tracking, host RPCs, result hashing, atomic precompile writes, and related build and tooling updates.

Changes

Runtime and protocol changes

Layer / File(s) Summary
Boolean expression support
executor/crates/common/src/expr/*, executor/crates/common/tests/expr.rs
Boolean tokens, AST nodes, parsing, evaluation, reserved-word handling, and expression tests are added.
Nested runtime state and limits
executor/src/exe/run.rs, executor/src/lib.rs, executor/src/rt/*, executor/src/wasi/genlayer_sdk/*
Nested permissions, storage modes, fee buckets, memory and deterministic-fuel budgets, recursion accounting, runner resolution, and host flushing are integrated into execution setup.
Nested CallContract routing and host protocol
executor/src/host/mod.rs, executor/src/wasi/genlayer_sdk/run.rs, executor/src/rt/vm/mod.rs, executor/crates/modules-interfaces/Cargo.toml
CallContract selects in-process or nested execution, exchanges length-prefixed host messages, validates nested replies, and uses shared result-hash logic.
Precompile persistence and registry lookup
executor/src/exe/precompile.rs, executor/src/rt/supervisor/actions.rs, executor/tests/precompile_lookup.rs
Precompiled artifacts use atomic replacement, require registered runner hashes, validate module existence, and have registry lookup tests.
Build, integration, and source-policy updates
.genvm-tool.py, .gitignore, executor/Cargo.toml, executor/codegen/data/public-abi.json, executor/src/wasi/mod.rs, flake.nix, support/scripts/check-source-text.py
Integration hash settings, scratch files, dev optimizations, ABI documentation, linker support, developer-shell comments, and environment-mutation checks are updated.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant VM
  participant Host
  participant NestedExecutor
  VM->>Host: resolve_callcontract_executor
  Host-->>VM: return routing payload
  VM->>Host: run_nested with NestedRunEnvelope
  Host->>NestedExecutor: forward nested execution
  NestedExecutor-->>Host: return NestedRunReply
  Host-->>VM: return validated nested result
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: reworking the manager API to support cross-major calls.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr/v0.3/feat/rework-manager-api

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kp2pml30
kp2pml30 force-pushed the pr/v0.3/feat/rework-manager-api branch 2 times, most recently from c0e3915 to 30fcc9e Compare July 29, 2026 12:03
* feat(sdk): call contracts of another major through the host ✨
* refactor(rt): bound recursion with a budget minted by the chain root ♻️
* refactor(exe): carry nested execution state as one explicit group ♻️
* fix(exe): fold the callee's small hash on the nested route 🐛🔒️
* feat(exe): refuse a crossing call while custom runners are loaded ✨
* fix(exe): hand a major this line cannot serve to the manager 🐛
* feat(host): write caller-supplied hello bytes and drop notify_finished ✨
* fix(supervisor): load precompiled modules only for registry runners 🔒️
* fix(fees): stop a zero execution budget aborting internally 🐛
* chore(exe): drop the unreachable dlsym linker helper 🔥
* test(integration): add routed, unservable-major and mismatch cases ✅
@kp2pml30
kp2pml30 force-pushed the pr/v0.3/feat/rework-manager-api branch from 30fcc9e to 96e7581 Compare July 29, 2026 13:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
executor/src/wasi/genlayer_sdk/tests.rs (1)

166-178: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider covering the other nested_run_ok rejection paths.

small_hash.len() != 32, ResultCode::InternalError, and the non-string VmError payload are all invariants worth pinning, since they guard cross-executor hash agreement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@executor/src/wasi/genlayer_sdk/tests.rs` around lines 166 - 178, Expand the
tests around nested_run_ok to cover each remaining rejection path: a small_hash
whose length is not 32, a nested result with ResultCode::InternalError, and a
VmError result carrying a non-string payload. Assert that nested_run_ok returns
an error for each case, reusing the existing NestedRunReply setup and keeping
the effect_free rejection test unchanged.
executor/src/rt/vm/storage.rs (1)

485-494: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

check_major doesn't use Self/HS — consider a free function.

Being an inherent associated fn of Storage<HS> forces callers into an unrelated turbofish (Storage::<StorageHostHolder>::check_major(..) in executor/src/wasi/genlayer_sdk/run.rs lines 148 and 501). A module-level pub fn check_major(contract_major: u8) in rt::vm::storage would read better and drop the bogus type parameter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@executor/src/rt/vm/storage.rs` around lines 485 - 494, Move check_major out
of the Storage<HS> inherent implementation into a module-level public function
in rt::vm::storage, since it does not use Self or HS. Update all callers,
including the usages in run.rs, to invoke the module function without the
Storage::<...> turbofish while preserving the existing validation behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@executor/src/wasi/genlayer_sdk/run.rs`:
- Around line 188-199: Update the nested protocol’s ResultCode::VmError handling
in the run flow to normalize and validate the materialized error code before
constructing public_abi::VmError. Reuse the existing strip_vm_error_detail and
validate_leader_vm_error helpers in this file, preserving the existing rejection
of non-string data and ensuring only canonical VM error codes reach the caller
and determinant fingerprint.

In `@support/scripts/check-source-text.py`:
- Around line 37-40: Extend the source-policy regexes in the check-source-text
logic to detect unqualified libc environment mutations, including direct calls,
imported symbols such as use libc::setenv, and aliased imports/calls for setenv,
unsetenv, and putenv. Add regression tests covering qualified, imported, and
aliased forms while preserving the existing env and libc-qualified matches.

---

Nitpick comments:
In `@executor/src/rt/vm/storage.rs`:
- Around line 485-494: Move check_major out of the Storage<HS> inherent
implementation into a module-level public function in rt::vm::storage, since it
does not use Self or HS. Update all callers, including the usages in run.rs, to
invoke the module function without the Storage::<...> turbofish while preserving
the existing validation behavior.

In `@executor/src/wasi/genlayer_sdk/tests.rs`:
- Around line 166-178: Expand the tests around nested_run_ok to cover each
remaining rejection path: a small_hash whose length is not 32, a nested result
with ResultCode::InternalError, and a VmError result carrying a non-string
payload. Assert that nested_run_ok returns an error for each case, reusing the
existing NestedRunReply setup and keeping the effect_free rejection test
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e0b170c9-9185-4b4e-bc8c-0489152c49b3

📥 Commits

Reviewing files that changed from the base of the PR and between 301d515 and 96e7581.

⛔ Files ignored due to path filters (56)
  • executor/Cargo.lock is excluded by !**/*.lock, !**/*.lock
  • executor/crates/common/Cargo.lock is excluded by !**/*.lock, !**/*.lock
  • executor/crates/modules-interfaces/Cargo.lock is excluded by !**/*.lock, !**/*.lock
  • tests/integration/claude/AGENT_PROMPT.md is excluded by !tests/**
  • tests/integration/claude/README.md is excluded by !tests/**
  • tests/integration/claude/agent/float_math/README.md is excluded by !tests/**
  • tests/integration/claude/agent/float_math/contract.py is excluded by !tests/**
  • tests/integration/claude/agent/float_math/float_math.jsonnet is excluded by !tests/**
  • tests/integration/claude/example/README.md is excluded by !tests/**
  • tests/integration/claude/example/example.jsonnet is excluded by !tests/**
  • tests/integration/claude/intelligence/EXPLORED_PATHS.md is excluded by !tests/**
  • tests/integration/claude/intelligence/TODO.md is excluded by !tests/**
  • tests/integration/claude/run-manager.sh is excluded by !tests/**
  • tests/integration/claude/run_test.py is excluded by !tests/**
  • tests/integration/exploit/disagree_in_sandbox/disagree_in_sandbox.jsonnet is excluded by !tests/**
  • tests/integration/exploit/unservable_major/unservable_major.0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/exploit/unservable_major/unservable_major.0_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/exploit/unservable_major/unservable_major.0_0_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/exploit/unservable_major/unservable_major.1.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/exploit/unservable_major/unservable_major.1_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/exploit/unservable_major/unservable_major.1_0_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/exploit/unservable_major/unservable_major.jsonnet is excluded by !tests/**
  • tests/integration/exploit/unservable_major/unservable_major_from.py is excluded by !tests/**
  • tests/integration/exploit/unservable_major/unservable_major_to.py is excluded by !tests/**
  • tests/integration/hello-world/hello_world/hello_world.0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/hello-world/hello_world/hello_world.jsonnet is excluded by !tests/**
  • tests/integration/hello-world/hello_world/hello_world_trivial.py is excluded by !tests/**
  • tests/integration/hello-world/hello_world_class_nondet/hello_world_class_nondet.0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/hello-world/hello_world_class_nondet/hello_world_class_nondet.jsonnet is excluded by !tests/**
  • tests/integration/hello-world/hello_world_class_nondet/hello_world_class_nondet.py is excluded by !tests/**
  • tests/integration/message/use_balance_zero_budget/use_balance_zero_budget.0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/message/use_balance_zero_budget/use_balance_zero_budget.0_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/message/use_balance_zero_budget/use_balance_zero_budget.jsonnet is excluded by !tests/**
  • tests/integration/message/use_balance_zero_budget/use_balance_zero_budget.py is excluded by !tests/**
  • tests/integration/misc/routed_call/routed_call.0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/misc/routed_call/routed_call.0_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/misc/routed_call/routed_call.0_0_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/misc/routed_call/routed_call.jsonnet is excluded by !tests/**
  • tests/integration/misc/routed_call/routed_call_from.py is excluded by !tests/**
  • tests/integration/misc/routed_call/routed_call_to.py is excluded by !tests/**
  • tests/integration/nasty-determinism/floats/contract.py is excluded by !tests/**
  • tests/integration/nasty-determinism/floats/floats.0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/nasty-determinism/floats/floats.jsonnet is excluded by !tests/**
  • tests/integration/runner/absent_runner_id/absent_runner_id.0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/runner/absent_runner_id/absent_runner_id.0_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/runner/absent_runner_id/absent_runner_id.0_1.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/runner/absent_runner_id/absent_runner_id.0_2.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/runner/absent_runner_id/absent_runner_id.jsonnet is excluded by !tests/**
  • tests/integration/runner/absent_runner_id/absent_runner_id.py is excluded by !tests/**
  • tests/integration/runner/major_mismatch/major_mismatch.3.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/runner/major_mismatch/major_mismatch.3_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/runner/major_mismatch/major_mismatch.jsonnet is excluded by !tests/**
  • tests/integration/storage/hello_world_class/hello_world_class.0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/storage/hello_world_class/hello_world_class.0_0.stdout is excluded by !**/*.stdout, !tests/**
  • tests/integration/storage/hello_world_class/hello_world_class.jsonnet is excluded by !tests/**
  • tests/integration/storage/hello_world_class/hello_world_class.py is excluded by !tests/**
📒 Files selected for processing (31)
  • .genvm-tool.py
  • .gitignore
  • executor/Cargo.toml
  • executor/codegen/data/host-fns.json
  • executor/codegen/data/public-abi.json
  • executor/crates/common/src/expr/evaluator.rs
  • executor/crates/common/src/expr/lexer.rs
  • executor/crates/common/src/expr/tokenizer.rs
  • executor/crates/common/src/expr/value.rs
  • executor/crates/common/src/host_fns.rs
  • executor/crates/common/src/lib.rs
  • executor/crates/common/tests/expr.rs
  • executor/crates/modules-interfaces/Cargo.toml
  • executor/src/exe/precompile.rs
  • executor/src/exe/run.rs
  • executor/src/host/mod.rs
  • executor/src/lib.rs
  • executor/src/rt/memlimiter.rs
  • executor/src/rt/mod.rs
  • executor/src/rt/supervisor/actions.rs
  • executor/src/rt/supervisor/mod.rs
  • executor/src/rt/vm/mod.rs
  • executor/src/rt/vm/storage.rs
  • executor/src/wasi/genlayer_sdk/message.rs
  • executor/src/wasi/genlayer_sdk/mod.rs
  • executor/src/wasi/genlayer_sdk/run.rs
  • executor/src/wasi/genlayer_sdk/tests.rs
  • executor/src/wasi/mod.rs
  • executor/tests/precompile_lookup.rs
  • flake.nix
  • support/scripts/check-source-text.py
💤 Files with no reviewable changes (3)
  • executor/codegen/data/host-fns.json
  • executor/crates/common/src/host_fns.rs
  • executor/src/wasi/mod.rs

Comment on lines +188 to +199
let run_ok = match reply.result.kind {
genvm_modules_interfaces::ResultCode::Return => rt::vm::RunOk::Return(reply.result.data),
genvm_modules_interfaces::ResultCode::UserError => {
rt::vm::RunOk::UserError(reply.result.data)
}
genvm_modules_interfaces::ResultCode::VmError => {
let data = reply.result.data.materialize()?;
let calldata::Value::Str(code) = data else {
anyhow::bail!("nested CallContract VM error is not a string");
};
rt::vm::RunOk::VMError(public_abi::VmError(std::borrow::Cow::Owned(code)), None)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Nested VmError codes are trusted verbatim.

The in-process/leader paths normalize and validate VM error codes (strip_vm_error_detail / validate_leader_vm_error in this file), but a code arriving over the nested protocol is wrapped into public_abi::VmError unchecked. An unknown or detail-carrying string then reaches the caller and the det fingerprint, and can trip the debug_assert! in strip_vm_error_detail if it later flows through that path. Consider validating/stripping here too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@executor/src/wasi/genlayer_sdk/run.rs` around lines 188 - 199, Update the
nested protocol’s ResultCode::VmError handling in the run flow to normalize and
validate the materialized error code before constructing public_abi::VmError.
Reuse the existing strip_vm_error_detail and validate_leader_vm_error helpers in
this file, preserving the existing rejection of non-string data and ensuring
only canonical VM error codes reach the caller and determinant fingerprint.

Comment on lines +37 to +40
re.compile(r'\benv::(?:set_var|remove_var)\b'),
re.compile(r'\blibc::(?:setenv|unsetenv|putenv)\b'),
# ... including when imported, which hides the `env::` prefix at the call.
re.compile(r'\buse\s+(?:std::)?env::\{?[^;]*\b(?:set_var|remove_var)\b'),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Cover imported and unqualified libc environment mutations.

The libc pattern only matches libc::setenv, libc::unsetenv, and libc::putenv. It misses common forms such as use libc::setenv; setenv(...) and direct setenv(...) calls, so prohibited environment mutation can bypass this source-policy check. Add matching patterns and regression tests for qualified, imported, and aliased calls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@support/scripts/check-source-text.py` around lines 37 - 40, Extend the
source-policy regexes in the check-source-text logic to detect unqualified libc
environment mutations, including direct calls, imported symbols such as use
libc::setenv, and aliased imports/calls for setenv, unsetenv, and putenv. Add
regression tests covering qualified, imported, and aliased forms while
preserving the existing env and libc-qualified matches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant